﻿using Agility.Web.Models.DomainModel;
using NUnit.Framework;
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Globalization;
using System.ServiceModel.DomainServices.Server;
using System.Collections.Generic;
using Agility.Web.Resources;

namespace Agility.Testing.Web.Requirements
{
    [TestFixture]
    public class EpicTests
    {
        Epic epic;
        Epic.EpicMetadata epicMetadata;
        string username;

        [TestFixtureSetUp]
        public void SetupTestFixture()
        {
        }

        [TestFixtureTearDown]
        public void TeardownTestFixture()
        {
        }

        [SetUp]
        public void SetupTest()
        {
            epic = Epic.CreateEpic(Guid.NewGuid(), "", "", DateTime.Today, "Dave");
            epicMetadata = new Epic.EpicMetadata();
        }

        [TearDown]
        public void TeardownTest()
        {
            epicMetadata = null;
        }

        [Test]
        [Category("UnitTest")]
        public void TestTitle()
        {
            string expected = "Title";
            epic.Title = expected;
            Assert.AreEqual(expected, epic.Title);
        }

        [Test]
        [Category("UnitTest")]
        public void TestDescription()
        {
            string expected = "Description";
            epic.Description = expected;
            Assert.AreEqual(expected, epic.Description);
        }

        [Test]
        [Category("UnitTest")]
        public void TestCreationDate()
        {
            DateTime today = DateTime.Today;
            Assert.AreEqual(today, epic.CreationDate);
        }

        [Test]
        [Category("UnitTest")]
        public void TestUsername()
        {
            string expected = "Dave";
            string actual = epic.RequestedBy;
            Assert.AreEqual(expected, actual);
        }

        [Test]
        [Category("UnitTest")]
        public void TestMetadataTypeAttribute()
        {
            // Arrange
            var actual = typeof(Epic).GetCustomAttributes(typeof(MetadataTypeAttribute), false)
                                        .Cast<MetadataTypeAttribute>()
                                        .FirstOrDefault();
            string missingMessage = "MetaDataAttribute is missing on Epic";
            string wrongTypeMessage = "MetadataTypeAttribute uses the wrong type on Epic";

            // Assert
            Assert.NotNull(actual, missingMessage);
            Assert.AreEqual(typeof(Epic.EpicMetadata), actual.MetadataClassType, wrongTypeMessage);
        }

        [Test]
        [Category("UnitTest")]
        public void TestKeyAttribute()
        {
            // Arrange
            var target = typeof(Epic.EpicMetadata).GetProperty("Id");
            var actual = target.GetCustomAttributes(typeof(KeyAttribute), false)
                                        .Cast<KeyAttribute>()
                                        .FirstOrDefault();
            string message = "RequiredAttribute is missing on Epic.Id";

            // Assert
            Assert.NotNull(actual, message);
        }

        [Test]
        [Category("UnitTest")]
        [TestCase("Title", TestName = "Title")]
        [TestCase("Description", TestName = "Description")]
        [TestCase("CreationDate", TestName = "CreationDate")]
        [TestCase("RequestedBy", TestName = "RequestedBy")]
        public void TestRequiredAttribute(string propertyName)
        {
            // Arrange
            var target = typeof(Epic.EpicMetadata).GetProperty(propertyName);
            var actual = target.GetCustomAttributes(typeof(RequiredAttribute), false)
                                        .Cast<RequiredAttribute>()
                                        .FirstOrDefault();
            string message = string.Format(CultureInfo.InvariantCulture, "RequiredAttribute is missing on Epic.{0}", propertyName);

            // Assert
            Assert.NotNull(actual, message);
        }

        [Test]
        [Category("UnitTest")]
        [TestCase("CreationDate", TestName = "CreationDate")]
        [TestCase("Id", TestName = "Id")]
        [TestCase("RequestedBy", TestName = "RequestedBy")]
        public void TestEditableAttribute(string propertyName)
        {
            // Arrange
            var target = typeof(Epic.EpicMetadata).GetProperty(propertyName);
            var actual = target.GetCustomAttributes(typeof(EditableAttribute), false)
                                        .Cast<EditableAttribute>()
                                        .FirstOrDefault();
            string missingMessage = string.Format(CultureInfo.InvariantCulture, "EditableAttribute is missing on Epic.{0}", propertyName);
            string valueMessage = string.Format(CultureInfo.InvariantCulture, "EditableAttribute is set incorrectly on Epic.{0}", propertyName);

            // Assert
            Assert.NotNull(actual, missingMessage);
            Assert.IsFalse(actual.AllowEdit, valueMessage);
        }

        [Test]
        [Category("UnitTest")]
        [TestCase("Title", 30, TestName = "Title")]
        [TestCase("Description", 250, TestName = "Description")]
        public void TestStringLengthAttribute(string propertyName, int expectedMaximumLength)
        {
            // Arrange
            var target = typeof(Epic.EpicMetadata).GetProperty(propertyName);
            var actual = target.GetCustomAttributes(typeof(StringLengthAttribute), false)
                                                    .Cast<StringLengthAttribute>()
                                                    .FirstOrDefault();
            string isMissingMessage = string.Format(CultureInfo.InvariantCulture, "StringLengthAttribute is missing on Epic.{0}", propertyName);
            string maximumLengthMessage = string.Format(CultureInfo.InvariantCulture, "MaximumLengthAttribute is not set correctly on Epic.{0}", propertyName); 

            // Assert
            Assert.NotNull(actual, isMissingMessage);
            Assert.AreEqual(expectedMaximumLength, actual.MaximumLength, maximumLengthMessage);
        }
        
        [Test]
        [Category("UnitTest")]
        [TestCase("CreationDate", true, 0, "EpicCreationDate", typeof(EpicResources), TestName = "CreationDate")]
        [TestCase("Title", true, 1, "EpicTitle", typeof(EpicResources), TestName = "Title")]
        [TestCase("Description", true, 2, "EpicDescription", typeof(EpicResources), TestName = "Description")]
        [TestCase("RequestedBy", true, 3, "EpicRequestedBy", typeof(EpicResources), TestName = "RequestedBy")]
        [TestCase("Id", false, 0, null, null, TestName = "Id")]
        public void TestDisplayAttribute(string propertyName, bool autoGenerate, int order, string name, Type resourceType)
        {
            // Arrange
            var target = typeof(Epic.EpicMetadata).GetProperty(propertyName);
            var actual = target.GetCustomAttributes(typeof(DisplayAttribute), false)
                                                    .Cast<DisplayAttribute>()
                                                    .FirstOrDefault();

            // Assert
            Assert.NotNull(actual, string.Format(CultureInfo.InvariantCulture, "DisplayAttribute is missing on Epic.{0}", propertyName));
            Assert.AreEqual(autoGenerate, actual.GetAutoGenerateField().GetValueOrDefault(true), string.Format(CultureInfo.InvariantCulture, "AutoGeneratingField is set incorrectly on Epic.{0}", propertyName));
            Assert.AreEqual(order, actual.GetOrder().GetValueOrDefault(0), string.Format(CultureInfo.InvariantCulture, "Order is set incorrectly on Epic.{0}", propertyName));
            Assert.AreEqual(name, actual.Name, string.Format(CultureInfo.InvariantCulture, "The resource name is set incorrectly on Epic.{0}", propertyName));
            Assert.AreEqual(resourceType, actual.ResourceType, string.Format(CultureInfo.InvariantCulture, "Epic.{0} is using the wrong resource file", propertyName));
        }

        [Test]
        [Category("UnitTest")]
        [TestCase("Id", TestName = "Id")]
        [TestCase("Title", TestName = "Title")]
        [TestCase("Description", TestName = "Description")]
        [TestCase("CreationDate", TestName = "CreationDate")]
        [TestCase("RequestedBy", TestName = "RequestedBy")]
        public void TestDataType(string propertyName)
        {
            var target = typeof(Epic).GetProperty(propertyName);
            var targetMetadata = typeof(Epic.EpicMetadata).GetProperty(propertyName);
            var expected = target.GetType();
            var actual = targetMetadata.GetType();

            // Assert
            Assert.AreEqual(expected, actual, string.Format(CultureInfo.InvariantCulture, "Type of property {0} differs in Epic ({1}) and EpicMetadata ({2})", propertyName, expected.ToString(), actual.ToString()));
        }
    }
}
